/**
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *   http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */

#include <math.h>
#include "base/log_defines.h"
#include "base/time_utils.h"
#include "core/common/view_utils.h"
#include "core/config/core_environment.h"
#include "core/css/constants_value.h"
#include "core/layout/layout.h"
#include "core/manager/weex_core_manager.h"
#include "core/moniter/render_performance.h"
#include "core/render/page/render_page.h"
#include "core/render/action/render_action_add_element.h"
#include "core/render/action/render_action_add_child_to_richtext.h"
#include "core/render/action/render_action_add_event.h"
#include "core/render/action/render_action_appendtree_createfinish.h"
#include "core/render/action/render_action_createbody.h"
#include "core/render/action/render_action_createfinish.h"
#include "core/render/action/render_action_layout.h"
#include "core/render/action/render_action_move_element.h"
#include "core/render/action/render_action_remove_element.h"
#include "core/render/action/render_action_remove_child_from_richtext.h"
#include "core/render/action/render_action_remove_event.h"
#include "core/render/action/render_action_render_success.h"
#include "core/render/action/render_action_update_attr.h"
#include "core/render/action/render_action_update_richtext_child_attr.h"
#include "core/render/action/render_action_update_style.h"
#include "core/render/action/render_action_update_richtext_child_style.h"
#include "core/render/action/render_action_trigger_vsync.h"
#include "core/render/manager/render_manager.h"
#include "core/render/node/factory/render_type.h"
#include "core/render/node/render_list.h"
#include "core/render/node/render_object.h"

namespace WeexCore {

    RenderPage::RenderPage(const std::string &page_id)
            : RenderPageBase(page_id, "platform"),
              viewport_width_(0),
              render_root_(nullptr),
              render_page_size_(),
              render_object_registers_() {
#if RENDER_LOG
        LOGD("[RenderPage] new RenderPage >>>> pageId: %s", pageId.c_str());
#endif

        this->render_page_size_.first =
                WXCoreEnvironment::getInstance()->DeviceWidth();
        this->render_page_size_.second = NAN;
        this->viewport_width_ = kDefaultViewPortWidth;
        this->device_width_ = WXCoreEnvironment::getInstance()->DeviceWidth();
    }

    RenderPage::~RenderPage() {
        //#if RENDER_LOG
        LOGE("[RenderPage] Delete RenderPage >>>> pageId: %s", page_id().c_str());
        //#endif

        this->render_object_registers_.clear();

        if (this->render_root_ != nullptr) {
            delete this->render_root_;
            this->render_root_ = nullptr;
        }
    }

    void RenderPage::CalculateLayout() {
        if (this->render_root_ == nullptr || !this->render_root_->ViewInit()) return;

#if RENDER_LOG
        LOGD("[RenderPage] CalculateLayout >>>> pageId: %s", mPageId.c_str());
#endif

        int64_t start_time = getCurrentTime();
        if (is_before_layout_needed_.load()) {
            this->render_root_->LayoutBeforeImpl();
        }
        this->render_root_->calculateLayout(this->render_page_size_);
        if (is_platform_layout_needed_.load()) {
            this->render_root_->LayoutPlatformImpl();
        }
        if (is_after_layout_needed_.load()) {
            this->render_root_->LayoutAfterImpl();
        }
        CssLayoutTime(getCurrentTime() - start_time);
        TraverseTree(this->render_root_, 0);
    }

    void RenderPage::TraverseTree(RenderObject *render, long index) {
        if (render == nullptr) return;

        if (render->hasNewLayout()) {
            SendLayoutAction(render, (int) index);
            render->setHasNewLayout(false);
        }

        for (auto it = render->ChildListIterBegin(); it != render->ChildListIterEnd();
             it++) {
            RenderObject *child = static_cast<RenderObject *>(*it);
            if (child != nullptr) {
                TraverseTree(child, it - render->ChildListIterBegin());
            }
        }
    }

    bool RenderPage::CreateRootRender(RenderObject *root) {
        if (root == nullptr) return false;

        set_is_dirty(true);
        SetRootRenderObject(root);

        if (isnan(this->render_root_->getStyleWidth())) {
            this->render_root_->setStyleWidthLevel(FALLBACK_STYLE);
            if (is_render_container_width_wrap_content())
                this->render_root_->setStyleWidthToNAN();
            else
                this->render_root_->setStyleWidth(
                        WXCoreEnvironment::getInstance()->DeviceWidth(), false);
        } else {
            this->render_root_->setStyleWidthLevel(CSS_STYLE);
        }
        PushRenderToRegisterMap(root);

        SendCreateBodyAction(root);
        return true;
    }

    void RenderPage::SetRootRenderObject(RenderObject *root) {
        if (root != nullptr) {
            this->render_root_ = root;
            this->render_root_->set_is_root_render();
        }
    }

    bool RenderPage::AddRenderObject(const std::string &parent_ref,
                                     int insert_posiotn, RenderObject *child) {
        RenderObject *parent = GetRenderObject(parent_ref);
        if (parent == nullptr || child == nullptr) {
            return false;
        }

        if (WeexCore::WXCoreEnvironment::getInstance()->isInteractionLogOpen()) {
            LOGD("wxInteractionAnalyzer: [weexcore][addElementStart],%s,%s,%s",
                 this->page_id().c_str(), child->type().c_str(), child->ref().c_str());
        }

        // add child to Render Tree
        insert_posiotn = parent->AddRenderObject(insert_posiotn, child);
        if (insert_posiotn < -1) {
            return false;
        }

        set_is_dirty(true);

        PushRenderToRegisterMap(child);
        SendAddElementAction(child, parent, insert_posiotn, false);

        Batch();
        if (WeexCore::WXCoreEnvironment::getInstance()->isInteractionLogOpen()) {
            LOGD("wxInteractionAnalyzer: [weexcore][addElementEnd],%s,%s,%s",
                 this->page_id().c_str(), child->type().c_str(), child->ref().c_str());
        }
        return true;
    }

    bool RenderPage::RemoveRenderObject(const std::string &ref) {
        RenderObject *child = GetRenderObject(ref);
        if (child == nullptr) return false;

        RenderObject *parent = child->parent_render();
        if (parent == nullptr) return false;

        set_is_dirty(true);
        parent->RemoveRenderObject(child);

        RemoveRenderFromRegisterMap(child);
        RenderObject *richtext = child->RichtextParent();
        if (richtext) {
            RenderObject *parent = child->parent_render();
            SendRemoveChildFromRichtextAction(ref, parent->type() == "richtext" ? nullptr : parent, richtext);
            richtext->markDirty();
            Batch();
        } else {
            SendRemoveElementAction(ref);
        }
        delete child;
        return true;
    }

    bool RenderPage::MoveRenderObject(const std::string &ref,
                                      const std::string &parent_ref, int index) {
        RenderObject *child = GetRenderObject(ref);
        if (child == nullptr) return false;

        RenderObject *old_parent = child->parent_render();
        RenderObject *new_parent = GetRenderObject(parent_ref);
        if (old_parent == nullptr || new_parent == nullptr) return false;

        if (old_parent->ref() == new_parent->ref()) {
            if (old_parent->IndexOf(child) == index) {
                return false;
            } else if (old_parent->IndexOf(child) < index) {
                index = index - 1;
            }
        }

        if (index > new_parent->getChildCount()) {
            std::stringstream msg;
            msg << "Out of array bounds when RenderPage::MoveRenderObject, specified index: "
                << index << "array size " << new_parent->getChildCount();

            WeexCore::WeexCoreManager::Instance()->getPlatformBridge()->platform_side()
                    ->ReportException(page_id().c_str(), "RenderPage::MoveRenderObject", msg.str().c_str());
            return false;
        }

        set_is_dirty(true);
        child->getParent()->removeChild(child);
        new_parent->addChildAt(child, index);

        SendMoveElementAction(ref, parent_ref, index);
        return true;
    }

    bool RenderPage::UpdateStyle(
            const std::string &ref,
            std::vector<std::pair<std::string, std::string>> *src) {
        RenderObject *render = GetRenderObject(ref);
        if (render == nullptr || src == nullptr || src->empty()) return false;

        set_is_dirty(true);

        std::vector<std::pair<std::string, std::string>> *style = nullptr;
        std::vector<std::pair<std::string, std::string>> *margin = nullptr;
        std::vector<std::pair<std::string, std::string>> *padding = nullptr;
        std::vector<std::pair<std::string, std::string>> *border = nullptr;
        bool inheriableLayout = false;

        bool flag = false;
        RenderObject *richtext = render->RichtextParent();

        if (richtext) {
            richtext->markDirty();
            style = new std::vector<std::pair<std::string, std::string>>();
            for (auto it: *src) {
                style->push_back(it);
            }
            flag = true;
            RenderObject *parent = render->parent_render();
            SendUpdateRichtextChildStyleAction(render, style, parent->type() == "richtext" ? nullptr : parent, richtext);
        } else {
            int result = WeexCoreManager::Instance()
                    ->getPlatformBridge()
                    ->platform_side()
                    ->HasTransitionPros(this->page_id_.c_str(), ref.c_str(), src);

            if (result == 1) {
                SendUpdateStyleAction(render, src, margin, padding, border);
            } else {
                for (auto iter = src->begin(); iter != src->end(); iter++) {
                    switch (render->UpdateStyle((*iter).first, (*iter).second)) {
                        case kTypeStyle:
                            if (style == nullptr) {
                                style = new std::vector<std::pair<std::string, std::string>>();
                            }
                            style->insert(style->end(), (*iter));
                            flag = true;
                            break;
                        case kTypeMargin:
                            if (margin == nullptr) {
                                margin = new std::vector<std::pair<std::string, std::string>>();
                            }
                            render->UpdateStyleInternal(
                                    (*iter).first, (*iter).second, 0, [=, &flag](float foo) {
                                        (*iter).second = to_string(foo);
                                        margin->insert(margin->end(), (*iter));
                                        flag = true;
                                    });
                            break;
                        case kTypePadding:
                            if (padding == nullptr) {
                                padding = new std::vector<std::pair<std::string, std::string>>();
                            }
                            render->UpdateStyleInternal(
                                    (*iter).first, (*iter).second, 0, [=, &flag](float foo) {
                                        (*iter).second = to_string(foo);
                                        padding->insert(padding->end(), (*iter));
                                        flag = true;
                                    });
                            break;
                        case kTypeBorder:
                            if (border == nullptr) {
                                border = new std::vector<std::pair<std::string, std::string>>();
                            }
                            render->UpdateStyleInternal(
                                    (*iter).first, (*iter).second, 0, [=, &flag](float foo) {
                                        (*iter).second = to_string(foo);
                                        border->insert(border->end(), (*iter));
                                        flag = true;
                                    });
                            break;
                        case kTypeInheritableLayout:
                            inheriableLayout = true;
                            break;
                        default:
                            break;
                    }
                }
            }
            if (reserve_css_styles_ || render == render_root_) {
                // If a page requires that all raw css styles saved, we merge to RenderObject's styles map
                render->MergeStyles(src);
            }

            if (style != nullptr || margin != nullptr || padding != nullptr ||
                border != nullptr || inheriableLayout) {
                SendUpdateStyleAction(render, style, margin, padding, border);
            }
        }
        Batch();

        if (src != nullptr) {
            src->clear();
            src->shrink_to_fit();
        }

        if (style != nullptr) {
            style->clear();
            style->shrink_to_fit();
            delete style;
            style = nullptr;
        }

        if (margin != nullptr) {
            margin->clear();
            margin->shrink_to_fit();
            delete margin;
            margin = nullptr;
        }

        if (padding != nullptr) {
            padding->clear();
            padding->shrink_to_fit();
            delete padding;
            padding = nullptr;
        }

        if (border != nullptr) {
            border->clear();
            border->shrink_to_fit();
            delete border;
            border = nullptr;
        }

        return flag;
    }

    bool RenderPage::UpdateAttr(
            const std::string &ref,
            std::vector<std::pair<std::string, std::string>> *attrs) {
        RenderObject *render = GetRenderObject(ref);
        if (render == nullptr || attrs == nullptr || attrs->empty()) return false;

        RenderObject *richtext = render->RichtextParent();
        if (richtext) {
            RenderObject *parent = render->parent_render();
            SendUpdateRichtextChildAttrAction(render, attrs, parent->type() == "richtext" ? nullptr : parent, richtext);
            richtext->markDirty();
        } else {
            set_is_dirty(true);
            SendUpdateAttrAction(render, attrs);
            for (auto iter = attrs->cbegin(); iter != attrs->cend(); iter++) {
                render->UpdateAttr((*iter).first, (*iter).second);
            }
        }
        Batch();
        if (attrs != nullptr) {
            attrs->clear();
            attrs->shrink_to_fit();
        }

        return true;
    }

    void RenderPage::SetDefaultHeightAndWidthIntoRootRender(
            const float default_width, const float default_height,
            const bool is_width_wrap_content, const bool is_height_wrap_content) {
        this->render_page_size_.first = default_width;
        this->render_page_size_.second = default_height;
        if (this->render_root_->getStyleWidthLevel() >= INSTANCE_STYLE) {
            this->render_root_->setStyleWidthLevel(INSTANCE_STYLE);
            if (is_width_wrap_content) {
                set_is_render_container_width_wrap_content(true);
                this->render_root_->setStyleWidthToNAN();
                this->render_page_size_.first = NAN;
            } else {
                this->render_root_->setStyleWidth(default_width, true);
            }
            set_is_dirty(true);
        }

        if (this->render_root_->getStyleHeightLevel() >= INSTANCE_STYLE) {
            if (!is_height_wrap_content) {
                this->render_root_->setStyleHeightLevel(INSTANCE_STYLE);
                this->render_root_->setStyleHeight(default_height);
                set_is_dirty(true);
            }
        }

        Batch();
    }

    bool RenderPage::AddEvent(const std::string &ref, const std::string &event) {
        RenderObject *render = GetRenderObject(ref);
        if (render == nullptr) return false;

        set_is_dirty(true);
        render->AddEvent(event);

        RenderAction *action = new RenderActionAddEvent(this->page_id_, ref, event);
        PostRenderAction(action);
        return true;
    }

    bool RenderPage::RemoveEvent(const std::string &ref, const std::string &event) {
        RenderObject *render = GetRenderObject(ref);
        if (render == nullptr) return false;

        set_is_dirty(true);
        render->RemoveEvent(event);

        RenderAction *action =
                new RenderActionRemoveEvent(this->page_id_, ref, event);
        PostRenderAction(action);
        return true;
    }

    bool RenderPage::CreateFinish() {
        if (this->render_root_ == nullptr) {
            return false;
        }

        set_is_dirty(true);
        Batch();
        SendCreateFinishAction();
        // RenderSuccess means the Dom created after executing script finishes layout
        // and render, it will be trigger even though body not yet attaches to parent.
        LayoutInner();
        SendRenderSuccessAction();
        return true;
    }

    void RenderPage::LayoutInner() {
        CalculateLayout();
        this->need_layout_.store(false);
        set_is_dirty(false);
    }

    void RenderPage::LayoutImmediately() {
        if (is_dirty() && kUseVSync) {
            LayoutInner();
        }
    }

    void RenderPage::PushRenderToRegisterMap(RenderObject *render) {
        if (render == nullptr) return;

        std::string ref = render->ref();
        this->render_object_registers_.insert(
                std::pair<std::string, RenderObject *>(ref, render));

        for (auto it = render->ChildListIterBegin(); it != render->ChildListIterEnd();
             it++) {
            RenderObject *child = static_cast<RenderObject *>(*it);
            if (child != nullptr) {
                PushRenderToRegisterMap(child);
            }
        }

        for (auto it: render->shadow_objects_) {
            PushRenderToRegisterMap(it);
        }
    }

    void RenderPage::RemoveRenderFromRegisterMap(RenderObject *render) {
        if (render == nullptr) return;

        this->render_object_registers_.erase(render->ref());

        for (auto it = render->ChildListIterBegin(); it != render->ChildListIterEnd();
             it++) {
            RenderObject *child = static_cast<RenderObject *>(*it);
            if (child != nullptr) {
                RemoveRenderFromRegisterMap(child);
            }
        }
    }

    void RenderPage::SendCreateBodyAction(RenderObject *render) {
        if (render == nullptr) return;

        RenderAction *action = new RenderActionCreateBody(page_id(), render);
        PostRenderAction(action);

        int i = 0;
        for (auto it = render->ChildListIterBegin(); it != render->ChildListIterEnd();
             it++) {
            RenderObject *child = static_cast<RenderObject *>(*it);
            if (child != nullptr) {
                SendAddElementAction(child, render, i, true);
            }
            ++i;
        }

        if (i > 0 && render->IsAppendTree()) {
            SendAppendTreeCreateFinish(render->ref());
        }
    }

    void RenderPage::SendAddElementAction(RenderObject *child, RenderObject *parent,
                                          int index, bool is_recursion,
                                          bool will_layout) {
        if (child == nullptr || parent == nullptr) return;
        if (parent != nullptr && parent->type() == WeexCore::kRenderRecycleList) {
            will_layout = false;
        }
        RenderObject *richtext = child->RichtextParent();
        if (!richtext) {
            RenderAction *action =
                    new RenderActionAddElement(page_id(), child, parent, index, will_layout);
            PostRenderAction(action);
        } else {
            SendAddChildToRichtextAction(child, parent->type() == "richtext" ? nullptr : parent, richtext);
            richtext->markDirty();
            return;
        }
        if (child->type() == "richtext") {
            for (auto it: child->get_shadow_objects()) {
                if (it) {
                    SendAddChildToRichtextAction(it, nullptr, child);
                }
            }
            child->markDirty();
            return;
        }

        int i = 0;
        for (auto it = child->ChildListIterBegin(); it != child->ChildListIterEnd();
             it++) {
            RenderObject *grandson = static_cast<RenderObject *>(*it);
            if (grandson != nullptr) {
                SendAddElementAction(grandson, child, i, true, will_layout);
            }
            ++i;
        }

        if (child->type() == WeexCore::kRenderRecycleList) {
            RenderList *render_list = static_cast<RenderList *>(child);
            std::vector<RenderObject *> &cell_slots = render_list->CellSlots();
            for (auto it = cell_slots.begin(); it != cell_slots.end(); it++) {
                RenderObject *grandson = static_cast<RenderObject *>(*it);
                if (grandson != nullptr) {
                    SendAddElementAction(grandson, child, -1, true, will_layout);
                }
                ++i;
            }
        }
        if (!is_recursion && i > 0 && child->IsAppendTree()) {
            SendAppendTreeCreateFinish(child->ref());
        }
    }

    void RenderPage::SendAddChildToRichtextAction(RenderObject *child, RenderObject *parent, RenderObject *richtext) {
        RenderAction *action = new RenderActionAddChildToRichtext(page_id(), child, parent, richtext);
        PostRenderAction(action);

        for (auto it: child->get_child_list()) {
            RenderObject *grandson = static_cast<RenderObject *>(it);
            if (grandson) {
                SendAddChildToRichtextAction(grandson, child, richtext);
            }
        }
    }

    void RenderPage::SendRemoveChildFromRichtextAction(const std::string &ref, RenderObject *parent, RenderObject *richtext) {
        RenderAction *action = new RenderActionRemoveChildFromRichtext(page_id(), ref, parent, richtext);
        PostRenderAction(action);
    }

    void RenderPage::SendRemoveElementAction(const std::string &ref) {
        RenderAction *action = new RenderActionRemoveElement(page_id(), ref);
        PostRenderAction(action);
    }

    void RenderPage::SendMoveElementAction(const std::string &ref,
                                           const std::string &parent_ref,
                                           int index) {
        RenderAction *action =
                new RenderActionMoveElement(page_id(), ref, parent_ref, index);
        PostRenderAction(action);
    }

    void RenderPage::SendLayoutAction(RenderObject *render, int index) {
        if (render == nullptr) return;

        RenderAction *action = new RenderActionLayout(page_id(), render, index);
        PostRenderAction(action);
    }

    void RenderPage::SendUpdateStyleAction(
            RenderObject *render,
            std::vector<std::pair<std::string, std::string>> *style,
            std::vector<std::pair<std::string, std::string>> *margin,
            std::vector<std::pair<std::string, std::string>> *padding,
            std::vector<std::pair<std::string, std::string>> *border) {
        RenderAction *action = new RenderActionUpdateStyle(
                page_id(), render->ref(), style, margin, padding, border);
        PostRenderAction(action);
    }

    void RenderPage::SendUpdateRichtextChildStyleAction(RenderObject *render, std::vector<std::pair<std::string, std::string>> *style,
                                                        RenderObject *parent, RenderObject *richtext) {
        RenderAction *action = new RenderActionUpdateRichtextChildStyle(
                page_id(), render->ref(), style, parent, richtext);
        PostRenderAction(action);

    }

    void RenderPage::SendUpdateAttrAction(
            RenderObject *render,
            std::vector<std::pair<std::string, std::string>> *attrs) {
        RenderAction *action =
                new RenderActionUpdateAttr(page_id(), render->ref(), attrs);
        PostRenderAction(action);
    }

    void RenderPage::SendUpdateRichtextChildAttrAction(
            RenderObject *render,
            std::vector<std::pair<std::string, std::string>> *attrs, RenderObject *parent, RenderObject *richtext) {
        RenderAction *action =
                new RenderActionUpdateRichtextChildAttr(page_id(), render->ref(), attrs, parent, richtext);
        PostRenderAction(action);
    }

    void RenderPage::SendUpdateAttrAction(
            RenderObject *render, std::map<std::string, std::string> *attrs) {
        std::vector<std::pair<std::string, std::string>> *vAttrs =
                new std::vector<std::pair<std::string, std::string>>();
        for (auto iter = attrs->cbegin(); iter != attrs->cend(); iter++) {
            vAttrs->insert(vAttrs->begin(), std::pair<std::string, std::string>(
                    iter->first, iter->second));
        }

        RenderAction *action =
                new RenderActionUpdateAttr(page_id(), render->ref(), vAttrs);
        PostRenderAction(action);

        if (vAttrs != nullptr) {
            vAttrs->clear();
            delete vAttrs;
            vAttrs = nullptr;
        }
    }

    void RenderPage::SendAppendTreeCreateFinish(const std::string &ref) {
        RenderAction *action = new RenderActionAppendTreeCreateFinish(page_id(), ref);
        PostRenderAction(action);
    }

    void RenderPage::Batch() {
        if ((kUseVSync && this->need_layout_.load()) || !kUseVSync) {
            LayoutInner();
        }
#if OS_IOS
        // vsync may stopped, trigger once
        RenderAction *action = new RenderActionTriggerVSync(page_id());
        PostRenderAction(action);
#endif
    }

    RenderObject *RenderPage::GetRenderObject(const std::string &ref) {
        std::map<std::string, RenderObject *>::iterator iter =
                this->render_object_registers_.find(ref);
        if (iter != this->render_object_registers_.end()) {
            return iter->second;
        } else {
            return nullptr;
        }
    }

    void RenderPage::OnRenderPageInit() {}

    void RenderPage::OnRenderProcessStart() {}

    void RenderPage::OnRenderProcessExited() {}

    void RenderPage::OnRenderProcessGone() {}

    void RenderPage::OnRenderPageClose() {}

    bool RenderPage::ReapplyStyles() {
        if (!reserve_css_styles_) {
            LOGE("CSS styles of page %s are dropped, unable to do reapply styles actions.", page_id().c_str());
            return false;
        }

        for (auto it = render_object_registers_.begin(); it != render_object_registers_.end(); ++it) {
            if (it->second == nullptr) {
                continue;
            }

            auto stylesMap = it->second->styles_;
            if (stylesMap != nullptr) {
                std::vector<std::pair<std::string, std::string>> *style = nullptr;
                std::vector<std::pair<std::string, std::string>> *margin = nullptr;
                std::vector<std::pair<std::string, std::string>> *padding = nullptr;
                std::vector<std::pair<std::string, std::string>> *border = nullptr;
                bool inheriableLayout = false;

                for (auto sit = stylesMap->begin(); sit != stylesMap->end(); ++sit) {
                    switch (it->second->UpdateStyle(sit->first, sit->second)) {
                        case kTypeStyle:
                            if (style == nullptr) {
                                style = new std::vector<std::pair<std::string, std::string>>();
                            }
                            style->insert(style->end(), std::make_pair(sit->first, sit->second));
                            break;
                        case kTypeMargin:
                            if (margin == nullptr) {
                                margin = new std::vector<std::pair<std::string, std::string>>();
                            }
                            it->second->UpdateStyleInternal(
                                    sit->first, sit->second, 0, [=](float foo) {
                                        margin->insert(margin->end(), std::make_pair(sit->first, to_string(foo)));
                                    });
                            break;
                        case kTypePadding:
                            if (padding == nullptr) {
                                padding = new std::vector<std::pair<std::string, std::string>>();
                            }
                            it->second->UpdateStyleInternal(
                                    sit->first, sit->second, 0, [=](float foo) {
                                        padding->insert(padding->end(), std::make_pair(sit->first, to_string(foo)));
                                    });
                            break;
                        case kTypeBorder:
                            if (border == nullptr) {
                                border = new std::vector<std::pair<std::string, std::string>>();
                            }
                            it->second->UpdateStyleInternal(
                                    sit->first, sit->second, 0, [=](float foo) {
                                        border->insert(border->end(), std::make_pair(sit->first, to_string(foo)));
                                    });
                            break;
                        case kTypeInheritableLayout:
                            inheriableLayout = true;
                            break;
                        default:
                            break;
                    }
                }

                if (style != nullptr || margin != nullptr || padding != nullptr ||
                    border != nullptr || inheriableLayout) {
                    SendUpdateStyleAction(it->second, style, margin, padding, border);
                }

                if (style != nullptr) {
                    delete style;
                }

                if (margin != nullptr) {
                    delete margin;
                }

                if (padding != nullptr) {
                    delete padding;
                }

                if (border != nullptr) {
                    delete border;
                }
            }
        }

        Batch();
        return true;
    }

    void RenderPage::set_is_dirty(bool dirty) {
        this->is_dirty_.store(dirty);
#if OS_ANDROID
        WeexCore::WeexCoreManager::Instance()->
                getPlatformBridge()->
                platform_side()->SetPageDirty(this->page_id().c_str(), dirty);
#endif
    }

}  // namespace WeexCore
